package cn.com.easy.sign;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.util.CollectionUtils;

import cn.com.easy.exception.BusinessException;
import cn.com.easy.pay.alipay.www.util.AlipayCore;
import cn.com.easy.utils.RSAUtils;

/**
 * http签名以及验签工具类
 * 
 * @author nibili 2017年8月30日
 * 
 */
public class HttpServletRequestSignUtils {

	/**
	 * 验签
	 * 
	 * @param req
	 * @param publicKey
	 * @return
	 * @author nibili 2017年8月30日
	 * @throws Exception
	 */
	public static boolean very(HttpServletRequest request, String publicKey) throws Exception {

		@SuppressWarnings("unchecked")
		Map<String, String[]> requestParams = request.getParameterMap();
		if (CollectionUtils.isEmpty(requestParams) == true) {
			throw new BusinessException("参数不能为空");
		}

		// 获取POST过来反馈信息
		Map<String, String> params = new HashMap<String, String>();
		for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
			String name = (String) iter.next();
			String[] values = (String[]) requestParams.get(name);
			String valueStr = "";
			for (int i = 0; i < values.length; i++) {
				valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
			}
			params.put(name, valueStr);
		}
		// 客户端传递的签名串
		String sign = "";
		if (params.get("sign") != null) {
			sign = params.get("sign");
		} else {
			throw new BusinessException("签名字符串不能为空");
		}
		// 过滤空值、sign与sign_type参数
		Map<String, String> sParaNew = paraFilter(params);
		// 获取待签名字符串
		String preSignStr = AlipayCore.createLinkString(sParaNew);
		// 获得签名验证结果
		boolean isSign = RSAUtils.verify(preSignStr, publicKey, sign);
		return isSign;
	}

	/**
	 * 生成要请求的参数数组 <br/>
	 * 签名参数为"sign"
	 * 
	 * @param sParaTemp
	 *            请求前的参数数组
	 * @param privateKey
	 * @return 要请求的参数数组
	 * @throws Exception
	 */
	public static String buildRequestParaLinkString(Map<String, String> paramMap, String privateKey) throws Exception {

		Map<String, String> sPara = buildRequestPara(paramMap, privateKey);
		String prestr = createLinkString(sPara); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串;
		return prestr;
	}

	/**
	 * 生成要请求给参数数组 <br/>
	 * 签名参数为"sign"
	 * 
	 * @param sParaTemp
	 *            请求前的参数数组
	 * @param privateKey
	 * @return 要请求的参数数组
	 * @throws Exception
	 */
	public static Map<String, String> buildRequestPara(Map<String, String> paramMap, String privateKey) throws Exception {
		// 除去数组中的空值和签名参数
		Map<String, String> sPara = paraFilter(paramMap);
		// 生成签名结果
		String mysign = buildRequestMysign(sPara, privateKey);

		// 签名结果与签名方式加入请求提交参数组中
		sPara.put("sign", mysign);
		return sPara;
	}

	/**
	 * 生成签名结果
	 * 
	 * @param sPara
	 *            要签名的数组
	 * @param privateKey
	 * @return 签名结果字符串
	 * @throws Exception
	 */
	private static String buildRequestMysign(Map<String, String> sPara, String privateKey) throws Exception {
		String prestr = createLinkString(sPara); // 把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
		String mysign = RSAUtils.sign(prestr, privateKey);
		return mysign;
	}

	/**
	 * 除去数组中的空值和签名参数
	 * 
	 * @param sArray
	 *            签名参数组
	 * @return 去掉空值与签名参数后的新签名参数组
	 */
	private static Map<String, String> paraFilter(Map<String, String> sArray) {

		Map<String, String> result = new HashMap<String, String>();

		if (sArray == null || sArray.size() <= 0) {
			return result;
		}

		for (String key : sArray.keySet()) {
			String value = sArray.get(key);
			if (value == null || value.equals("") || key.equalsIgnoreCase("sign") || key.equalsIgnoreCase("sign_type")) {
				continue;
			}
			result.put(key, value);
		}

		return result;
	}

	/**
	 * 把数组所有元素排序，并按照“参数=参数值”的模式用“&”字符拼接成字符串
	 * 
	 * @param params
	 *            需要排序并参与字符拼接的参数组
	 * @return 拼接后字符串
	 */
	private static String createLinkString(Map<String, String> params) {

		List<String> keys = new ArrayList<String>(params.keySet());
		Collections.sort(keys);

		String prestr = "";

		for (int i = 0; i < keys.size(); i++) {
			String key = keys.get(i);
			String value = params.get(key);

			if (i == keys.size() - 1) {// 拼接时，不包括最后一个&字符
				prestr = prestr + key + "=" + value;
			} else {
				prestr = prestr + key + "=" + value + "&";
			}
		}

		return prestr;
	}
}
